package com.shangxia.monomer.study.thread.forkjoin;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.LongStream;

/**
 * @ProjectName: monomer
 * @ClassName: ForkJoinDemo
 * @Time: 2021/10/3
 * @Author: zhouy
 * @Description:
 * @Experience:
 */

@Slf4j
public class ForkJoinDemo {


    public static void main(String[] args) {
        for (int i = 0; i < 1; i++) {
            Long start = System.currentTimeMillis();
            System.out.println(test1(i));
            Long end = System.currentTimeMillis();
            System.out.println((end - start) + "ms");
            System.out.println();
        }
    }

    public static Long test1(int type) {
        Long result = 0L;
        if (type == 0) {

            for (Long i = 0L; i < Long.valueOf(10L * Integer.MAX_VALUE); i++) {
                result += i;
            }
        } else if (type == 1) {//159056ms
            ForkJoinDemoTask task = new ForkJoinDemoTask(0L, Long.valueOf(10L * Integer.MAX_VALUE));
            ForkJoinPool pool = new ForkJoinPool();
            ForkJoinTask<Long> submit = pool.submit(task);
            try {
                result = submit.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        } else {
            result = LongStream.range(0L, Long.valueOf(10L * Integer.MAX_VALUE)).reduce(0L, Long::sum);
        }
        return result;
    }
}

@AllArgsConstructor
@NoArgsConstructor
@Data
class ForkJoinDemoTask extends RecursiveTask<Long> {

    private Long start;
    private Long end;
    private static final Integer MAX = Integer.MAX_VALUE;
    private ThreadLocal<Long> local = new ThreadLocal<>();

    public ForkJoinDemoTask(Long start, Long end) {
        this.start = start;
        this.end = end;
    }

    @SneakyThrows
    @Override
    protected Long compute() {
        Long result = 0L;
        if (end - start < MAX) {
            local.set(System.currentTimeMillis());
            for (Long i = start; i < end; i++) {
                result += i;
            }
            System.out.println(Thread.currentThread().getName() + ": " + (System.currentTimeMillis() - local.get())+"ms");
        } else {
            Long middle = (start + end) / 2;
            ForkJoinDemoTask task1 = new ForkJoinDemoTask(start, middle);
            task1.fork();
            ForkJoinDemoTask task2 = new ForkJoinDemoTask(middle, end);
            task2.fork();
            result = task1.get() + task2.get();
        }
        return result;
    }
}
